/****************************************************************/
/*																*/
/*  UserAccountPage.cpp											*/
/*																*/
/*  Implementation of the CUserAccountPage class.				*/
/*	This class is a part of Quick 'n Easy FTP Server.			*/
/*																*/
/*  Programmed by Pablo van der Meer							*/
/*  Copyright Pablo Software Solutions 2005						*/
/*	http://www.pablosoftwaresolutions.com						*/
/*																*/
/*  Last updated: May 28, 2005									*/
/*																*/
/****************************************************************/


#include "stdafx.h"
#include "FTPServerApp.h"
#include "ftpserver.h"
#include "UserAccountPage.h"
#include "AddUserDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern CFTPServer theServer;

CUserAccountPage::CUserAccountPage(CWnd* pParent /*=NULL*/)
	: CDialogResize(CUserAccountPage::IDD, pParent)
{
	//{{AFX_DATA_INIT(CUserAccountPage)
	m_bDisableAccount = FALSE;
	m_strHomeDirectory = _T("");
	m_strPassword = _T("");
	m_bAllowCreateDirectory = FALSE;
	m_bAllowDelete = FALSE;
	m_bAllowRename = FALSE;
	m_bAllowUpload = FALSE;
	m_bAllowDownload = FALSE;
	//}}AFX_DATA_INIT
	m_bModified = FALSE;
}


void CUserAccountPage::DoDataExchange(CDataExchange* pDX)
{
	CDialogResize::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CUserAccountPage)
	DDX_Control(pDX, IDC_UPDATE, m_btnUpdate);
	DDX_Control(pDX, IDC_EDIT_USER, m_btnEdit);
	DDX_Control(pDX, IDC_DEL_USER, m_btnDel);
	DDX_Control(pDX, IDC_ADD_USER, m_btnAdd);
	DDX_Control(pDX, IDC_USERS, m_UsersList);
	DDX_Check(pDX, IDC_DISABLE_ACCOUNT, m_bDisableAccount);
	DDX_Text(pDX, IDC_HOME_DIRECTORY, m_strHomeDirectory);
	DDX_Text(pDX, IDC_PASSWORD, m_strPassword);
	DDX_Check(pDX, IDC_CREATE_DIR, m_bAllowCreateDirectory);
	DDX_Check(pDX, IDC_DELETE, m_bAllowDelete);
	DDX_Check(pDX, IDC_UPLOAD, m_bAllowUpload);
	DDX_Check(pDX, IDC_DOWNLOAD, m_bAllowDownload);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CUserAccountPage, CDialogResize)
	//{{AFX_MSG_MAP(CUserAccountPage)
	ON_BN_CLICKED(IDC_ADD_USER, OnAddUser)
	ON_BN_CLICKED(IDC_EDIT_USER, OnEditUser)
	ON_BN_CLICKED(IDC_DEL_USER, OnDelUser)
	ON_NOTIFY(NM_DBLCLK, IDC_USERS, OnDblclkUsers)
	ON_NOTIFY(NM_CLICK, IDC_USERS, OnClickUsers)
	ON_NOTIFY(LVN_KEYDOWN, IDC_USERS, OnKeydownUsers)
	ON_BN_CLICKED(IDC_UPDATE, OnUpdate)
	ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
	ON_EN_CHANGE(IDC_PASSWORD, OnSomethingChanged)
	ON_BN_CLICKED(IDC_DISABLE_ACCOUNT, OnDisableAccount)
	ON_EN_CHANGE(IDC_HOME_DIRECTORY, OnSomethingChanged)
	ON_BN_CLICKED(IDC_DOWNLOAD, OnSomethingChanged)
	ON_BN_CLICKED(IDC_UPLOAD, OnSomethingChanged)
	ON_BN_CLICKED(IDC_DELETE, OnSomethingChanged)
	ON_BN_CLICKED(IDC_CREATE_DIR, OnSomethingChanged)
	//}}AFX_MSG_MAP
	ON_UPDATE_COMMAND_UI(IDC_UPDATE, OnUpdateModified)
END_MESSAGE_MAP()


BEGIN_DLGRESIZE_MAP(CUserAccountPage)
	DLGRESIZE_CONTROL(IDC_USERS, DLSZ_SIZE_Y)
	DLGRESIZE_CONTROL(IDC_ADD_USER, DLSZ_MOVE_Y)
	DLGRESIZE_CONTROL(IDC_EDIT_USER, DLSZ_MOVE_Y)
	DLGRESIZE_CONTROL(IDC_DEL_USER, DLSZ_MOVE_Y)
	DLGRESIZE_CONTROL(IDC_UPDATE, DLSZ_MOVE_X | DLSZ_MOVE_Y)
	DLGRESIZE_CONTROL(IDC_HOME_DIRECTORY, DLSZ_SIZE_X)
END_DLGRESIZE_MAP()


/********************************************************************/
/*																	*/
/* Function name : OnInitDialog										*/		
/* Description   : Called by the framework in response to the		*/
/*				   WM_INITDIALOG message.							*/
/*																	*/
/********************************************************************/
BOOL CUserAccountPage::OnInitDialog() 
{
	CDialogResize::OnInitDialog();
	
	InitResizing(FALSE, FALSE, WS_CLIPCHILDREN);

	CRect rc;
	m_UsersList.GetClientRect(rc);
	m_UsersList.InsertColumn(0, "Users", LVCFMT_LEFT, rc.Width()-GetSystemMetrics(SM_CXBORDER)*2);

	DWORD dwStyle = m_UsersList.GetExtendedStyle();
	dwStyle |= (LVS_EX_FULLROWSELECT);
    m_UsersList.SetExtendedStyle(dwStyle);

	theServer.m_UserManager.GetUserList(m_UserArray);

	// fill user list
	for (int i=0; i < m_UserArray.GetSize(); i++)
	{
		int nIndex = m_UsersList.InsertItem(0, m_UserArray[i].m_strName, 0);
		m_UsersList.SetItemData(nIndex, i);
	}

	// create and attach imagelist
	m_ImageList.Create(16, 16, ILC_MASK, 1, 1);
	
	HICON hIcon = AfxGetApp()->LoadIcon(IDI_USER);
	m_ImageList.Add(hIcon);
	DestroyIcon(hIcon);

	m_UsersList.SetImageList(&m_ImageList, LVSIL_SMALL);

	// select preferred user ?
	if (!m_strUserName.IsEmpty())
	{
		LVFINDINFO info;
	
		info.flags = LVFI_STRING;
		info.psz = (LPCTSTR)m_strUserName;

		int nIndex = m_UsersList.FindItem(&info);
		m_UsersList.SetItemState(nIndex ,LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
	}
	else
	{
		m_UsersList.SetItemState(0 ,LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
	}

	((CEdit *)GetDlgItem(IDC_PASSWORD))->SetPasswordChar('*');
	((CEdit *)GetDlgItem(IDC_PASSWORD))->SetMargins(0,0);

	m_btnAdd.SetIcon(IDI_ADD, 16, 16);
	m_btnEdit.SetIcon(IDI_USER, 16, 16);
	m_btnDel.SetIcon(IDI_DELUSER, 16, 16);
	m_btnUpdate.SetIcon(IDI_UPDATE, 16, 16);
	
	OnSelchangeUserlist();

	SetModified(FALSE);
	return TRUE;
}


/********************************************************************/
/*																	*/
/* Function name : OnAddUser										*/
/* Description   : Add a new user account.							*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnAddUser() 
{
	CAddUserDlg dlg;
	if (dlg.DoModal() == IDOK)
	{
		for (int i=0; i<m_UsersList.GetItemCount(); i++)
		{
			CString strName;
			strName = m_UsersList.GetItemText(i, 0);
			if (strName.CompareNoCase(dlg.m_strName) == 0)
			{
				AfxMessageBox("Sorry, this user already exists!");
				return;
			}
		}

		CUser user;
		user.m_strName = dlg.m_strName;
		user.m_strPassword = "";

		int nItem = m_UsersList.InsertItem(0, user.m_strName, 0);
		if (nItem <= m_nPreviousIndex)
			m_nPreviousIndex++;

		// add home directory item
		user.m_bAllowCreateDirectory = FALSE;
		user.m_bAllowDelete = FALSE;
		user.m_bAllowDownload = TRUE;
		user.m_bAllowRename = FALSE;
		user.m_bAllowUpload = FALSE;
		user.m_strHomeDirectory = "";

		int index = m_UserArray.Add(user);
		
		m_UsersList.SetItemData(nItem, index);
		m_UsersList.SetItemState(nItem, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 

		OnSelchangeUserlist();

		// update user manager
		theServer.m_UserManager.UpdateUserList(m_UserArray);
		SetModified();

		// launch directory browser
		PostMessage(WM_COMMAND, IDC_BROWSE);
	} 
}


/********************************************************************/
/*																	*/
/* Function name : OnEditUser										*/
/* Description   : Edit user account name.							*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnEditUser() 
{
	// get selected user
	int nSelIndex = m_UsersList.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
    if(nSelIndex == -1)
        return;

	int nUserIndex = m_UsersList.GetItemData(nSelIndex);

	CAddUserDlg dlg;
	dlg.m_strTitle = "Edit User";
	dlg.m_strName = m_UserArray[nUserIndex].m_strName;

	if (dlg.DoModal() == IDOK)
	{
		// check if user already exists
		for (int i=0; i<m_UsersList.GetItemCount(); i++)
		{
			if (i != nSelIndex)
			{
				CString strName;
				strName = m_UsersList.GetItemText(i, 0);
				if (strName.CompareNoCase(dlg.m_strName) == 0)
				{
					AfxMessageBox("Sorry, this user already exists!");
					return;
				}
			}
		}

		m_UserArray[nUserIndex].m_strName = dlg.m_strName;

		m_UsersList.DeleteItem(nSelIndex);
		nSelIndex = m_UsersList.InsertItem(0, dlg.m_strName, 0);

		m_UsersList.SetItemData(nSelIndex, nUserIndex);
		m_UsersList.SetItemState(nSelIndex, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
		m_nPreviousIndex = nSelIndex;
		
		OnSelchangeUserlist();

		// update user manager
		theServer.m_UserManager.UpdateUserList(m_UserArray);
		SetModified(FALSE);
	} 
}


/********************************************************************/
/*																	*/
/* Function name : OnDblclkUsers									*/
/* Description   : Edit user account name.							*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnDblclkUsers(NMHDR* pNMHDR, LRESULT* pResult) 
{
	OnEditUser();
	*pResult = 0;
}


/********************************************************************/
/*																	*/
/* Function name : OnDelUser										*/
/* Description   : Delete user account.								*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnDelUser() 
{
	int nSelIndex = m_UsersList.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
    if(nSelIndex == -1)
        return;

	CString strText;

	strText.Format("Are you sure you want to delete '%s'?", m_UsersList.GetItemText(nSelIndex, 0));
	if (MessageBox(strText, "FTP Server", MB_YESNO | MB_ICONQUESTION) != IDYES)
	{
		return;
	}

	int nUserIndex = m_UsersList.GetItemData(nSelIndex);

	// remove user from array
	m_UserArray.RemoveAt(nUserIndex);

	m_nPreviousIndex = -1;
	// update item data values
	
	m_UsersList.SetRedraw(FALSE);
	m_UsersList.DeleteAllItems();
	
	// update user list
	for (int i=0; i < m_UserArray.GetSize(); i++)
	{
		int nIndex = m_UsersList.InsertItem(0, m_UserArray[i].m_strName, 0);
		m_UsersList.SetItemData(nIndex, i);
	}	
	m_UsersList.SetRedraw(TRUE);

	// update user manager
	theServer.m_UserManager.UpdateUserList(m_UserArray);
	SetModified(FALSE);

	m_UsersList.SetItemState(nSelIndex-1, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
	OnSelchangeUserlist();
}


/********************************************************************/
/*																	*/
/* Function name : OnSelchangeUserlist								*/
/* Description   : Selection in the user listcontrol has changed.	*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnSelchangeUserlist() 
{
	if (m_bModified && m_nPreviousIndex != -1)
	{
		if (MessageBox("User Account has changed.\n\nDo you want to save the changes?", "FTP Server", MB_YESNO | MB_ICONQUESTION) == IDYES)
		{
			if (!UpdateAccount(m_nPreviousIndex))
				return;
		}
	}

	// get selected user
	int nSelIndex = m_UsersList.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
	if (nSelIndex != -1)
	{
		int nUserIndex = m_UsersList.GetItemData(nSelIndex);

		// update dialog variables
		m_strPassword = m_UserArray[nUserIndex].m_strPassword;
		m_bDisableAccount = m_UserArray[nUserIndex].m_bAccountDisabled;
	
		m_strHomeDirectory = m_UserArray[nUserIndex].m_strHomeDirectory;
		m_bAllowCreateDirectory = m_UserArray[nUserIndex].m_bAllowCreateDirectory;
		m_bAllowDelete = m_UserArray[nUserIndex].m_bAllowDelete;
		m_bAllowDownload = m_UserArray[nUserIndex].m_bAllowDownload;
		m_bAllowRename = m_UserArray[nUserIndex].m_bAllowRename;
		m_bAllowUpload = m_UserArray[nUserIndex].m_bAllowUpload;

		UpdateData(FALSE);

		CWnd* pWnd = GetWindow(GW_CHILD);
		while (pWnd)
		{
			pWnd->EnableWindow(TRUE);
			pWnd = pWnd->GetWindow(GW_HWNDNEXT);
		}

		OnDisableAccount();

		m_nPreviousIndex = nSelIndex;
	}
	else
	{
		// nothing selected...
		m_strPassword = "";
		m_bDisableAccount = FALSE;
		m_strHomeDirectory = "";
		m_bAllowCreateDirectory = FALSE;
		m_bAllowDelete = FALSE;
		m_bAllowDownload = FALSE;
		m_bAllowRename = FALSE;
		m_bAllowUpload = FALSE;
		UpdateData(FALSE);

		CWnd* pWnd = GetWindow(GW_CHILD);
		while (pWnd)
		{
			if ((pWnd->GetDlgCtrlID() != IDC_USERS) &&
				(pWnd->GetDlgCtrlID() != IDC_ADD_USER))
			{
				pWnd->EnableWindow(FALSE);
			}
			pWnd = pWnd->GetWindow(GW_HWNDNEXT);
		}

		// don't save data on next selection (Thanks to Edwin Brunner)
		m_nPreviousIndex = -1;
	}

	UpdateDialogControls(this, FALSE);
	
	SetModified(FALSE);
}


/********************************************************************/
/*																	*/
/* Function name : OnClickUsers										*/
/* Description   : Selection in the user listcontrol has changed.	*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnClickUsers(NMHDR* pNMHDR, LRESULT* pResult) 
{
	OnSelchangeUserlist();	
	*pResult = 0;
}


/********************************************************************/
/*																	*/
/* Function name : OnKeydownUsers									*/
/* Description   : Selection in the user listcontrol has changed.	*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnKeydownUsers(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;

    // get index of selected item
	int nIndex = m_UsersList.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
    
    if(nIndex == -1)
        return;

	if (pLVKeyDow->wVKey == VK_DOWN)
	{
		if (m_UsersList.GetItemCount()-1 > nIndex)
		{
			m_UsersList.SetItemState(nIndex + 1, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
		}
	}
	else
	if (pLVKeyDow->wVKey == VK_UP)
	{
		if (nIndex > 0)
		{
			m_UsersList.SetItemState(nIndex - 1, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
		}
	}
	else
	if (pLVKeyDow->wVKey == VK_NEXT)
	{
		m_UsersList.SetItemState(m_UsersList.GetItemCount()-1, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
	}
	else
	if (pLVKeyDow->wVKey == VK_PRIOR)
	{
		m_UsersList.SetItemState(0, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
	}
	OnSelchangeUserlist();

	*pResult = 1;
}


/********************************************************************/
/*																	*/
/* Function name : UpdateAccount									*/
/* Description   : Update currently selected account				*/
/*																	*/
/********************************************************************/
BOOL CUserAccountPage::UpdateAccount(int nSelIndex)
{
	if (nSelIndex == -1)
	{
		// get selected user
		nSelIndex = m_UsersList.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); 
	}

	if (nSelIndex != -1)
	{
		UpdateData();

		int nUserIndex = m_UsersList.GetItemData(nSelIndex);

		m_UserArray[nUserIndex].m_strPassword = m_strPassword;
		m_UserArray[nUserIndex].m_bAccountDisabled = m_bDisableAccount;

		// check if it's a valid directory
		if (GetFileAttributes(m_strHomeDirectory) == 0xFFFFFFFF)
		{
			MessageBox("Please enter a valid home directory", "FTP Server", MB_OK | MB_ICONEXCLAMATION);
			GetDlgItem(IDC_HOME_DIRECTORY)->SetFocus();
			m_UsersList.SetItemState(m_nPreviousIndex, LVIS_SELECTED | LVIS_FOCUSED , LVIS_SELECTED | LVIS_FOCUSED); 
			return FALSE;
		}

		m_UserArray[nUserIndex].m_strHomeDirectory = m_strHomeDirectory;
		m_UserArray[nUserIndex].m_bAllowCreateDirectory = m_bAllowCreateDirectory;
		m_UserArray[nUserIndex].m_bAllowDelete = m_bAllowDelete;
		m_UserArray[nUserIndex].m_bAllowDownload = m_bAllowDownload;
		m_UserArray[nUserIndex].m_bAllowRename = m_bAllowRename;
		m_UserArray[nUserIndex].m_bAllowUpload = m_bAllowUpload;
		
		// update user manager
		theServer.m_UserManager.UpdateUserList(m_UserArray);
		return TRUE;
	}
	return FALSE;
}


/********************************************************************/
/*																	*/
/* Function name : OnUpdate											*/
/* Description   : Update selected account							*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnUpdate() 
{
	if (UpdateAccount() == TRUE)
	{
		SetModified(FALSE);
	}
}


/********************************************************************/
/*																	*/
/* Function name : OnUpdateModified									*/
/* Description   : Update 'Update' button state						*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnUpdateModified(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_bModified);
}


/********************************************************************/
/*																	*/
/* Function name : SetModified										*/
/* Description   : Set modified status								*/
/*																	*/
/********************************************************************/
void CUserAccountPage::SetModified(BOOL bModified)
{
	m_bModified = bModified;
	UpdateDialogControls(this, FALSE);
}


/********************************************************************/
/*																	*/
/* Function name : OnDisableAccount									*/
/* Description   : Disable account has been clicked					*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnDisableAccount() 
{
	m_bDisableAccount = IsDlgButtonChecked(IDC_DISABLE_ACCOUNT);
	CWnd* pWnd = GetWindow(GW_CHILD);
	while (pWnd)
	{
		if ((pWnd->GetDlgCtrlID() != IDC_DISABLE_ACCOUNT) &&
		    (pWnd->GetDlgCtrlID() != IDC_USERS) &&
			(pWnd->GetDlgCtrlID() != IDC_ADD_USER) &&
			(pWnd->GetDlgCtrlID() != IDC_EDIT_USER) &&
			(pWnd->GetDlgCtrlID() != IDC_DEL_USER) &&
			(pWnd->GetDlgCtrlID() != IDC_UPDATE))
		{
			pWnd->EnableWindow(!m_bDisableAccount);
		}
		pWnd = pWnd->GetWindow(GW_HWNDNEXT);
	}
}


/********************************************************************/
/*																	*/
/* Function name : OnBrowse											*/
/* Description   : Browse for Root Folder							*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnBrowse() 
{
	CString strDir = BrowseForFolder(m_hWnd, "Select a home directory:", BIF_RETURNONLYFSDIRS);
	if (!strDir.IsEmpty())
	{
		m_strHomeDirectory = strDir;
		UpdateData(FALSE);
	}	
}


/********************************************************************/
/*																	*/
/* Function name : OnSomethingChanged								*/
/* Description   : Something is changed								*/
/*																	*/
/********************************************************************/
void CUserAccountPage::OnSomethingChanged() 
{
	UpdateData();
	SetModified();
}
